﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace SyncUdp
{
    using SyncUdp.CommonDefined;
    using SyncUdp.Enum;
    using SyncUdp.Event;
    using SyncUdp.Event.GameEvent;
    using SyncUdp.Interface;
    using SyncUdp.MethodExtension;
    using SyncUdp.Model;
    using SyncUdp.Network;
    using SyncUdp.UI;
    using System;
    using InspectionRes = Enum.MainMenuInputsInspectionResult;

    public interface IGameManager : ISingleton
    {
        public ArchitectureController Architecture { get; }

        /// <summary>
        /// 是否为编辑器模式下
        /// </summary>
        public bool IsEditorMode { get; }

        public CommonDataSO CommonData { get; }

        public AllPathsSO AllPaths { get; }

        public void Quit();

        /// <summary>
        /// 创建游戏
        /// </summary>
        /// <param name="failedMsg">如果失败则赋值此参数为错误消息</param>
        /// <returns></returns>
        public bool CreateGame(ref string failedMsg);

        /// <summary>
        /// 加入游戏
        /// </summary>
        /// <param name="failedMsg">如果失败则赋值此参数为错误消息</param>
        /// <returns></returns>
        public void JoinGame(Action<bool, string> onCompleted);

        public void CloseGame();
    }

    public class GameManager : AbstractSingleton, IGameManager
    {
        /// <summary>
        /// 是否处在游戏中
        /// </summary>
        bool _isInGame;

        int _id;

        ArchitectureController _architecture;
        AllPathsSO _allPath;
        CommonDataSO _commonData;
        INetworkSystem _network;

        public GameManager(ArchitectureController architecture) => _architecture = architecture; 

        string TransformInspectionRes(InspectionRes res)
        {
            switch (res)
            {
                case InspectionRes.None: return null;
                case InspectionRes.IPError: return "IP 填写错误！";
                case InspectionRes.PortError: return "端口号填写错误！";
                case InspectionRes.MaxCountError: return "最大人数填写错误！";
                case InspectionRes.PlayerNameError: return "玩家名字错误！";
                case InspectionRes.NotAvailable: return "游戏人数已满！";
                case InspectionRes.NotRespondedible: return "服务器未响应！";
                default: return "未知错误……";
            }
        }

        #region 方法实现
        public AllPathsSO AllPaths { get { return _allPath; } }

        public CommonDataSO CommonData { get => _commonData; }

        public bool IsEditorMode { get; private set; }

        public float ServerDispatchesTime { get; private set; }

        public float UnitsMultiplier { get; private set; }

        public ArchitectureController Architecture => _architecture;

        protected override void OnInit()
        {
            _isInGame = false;
            _id = UnityEngine.Random.Range(0, 100);
            // TODO：这种设定应放入 SO 中
            // 每 66ms 转发，频率大约为 15 帧
            ServerDispatchesTime = 1 / 15f;
            UnitsMultiplier = 0.01f;
            _network = this.GetInstance<INetworkSystem>();
            var resMgr = this.GetInstance<IResourceManager>();
            _allPath = resMgr.Load<AllPathsSO>("ScriptableObjects/AllPathsSO");
            _commonData = resMgr.Load<CommonDataSO>(_allPath.commonDataSettingSOPath);

            IsEditorMode = false;
#if UNITY_EDITOR
            IsEditorMode = true;
            if (IsEditorMode)
                UnityEditor.EditorApplication.playModeStateChanged += state =>
                {
                    if (state == UnityEditor.PlayModeStateChange.ExitingPlayMode)
                        SendEvent(new GameQuitEvent());
                };
            else
#endif
                Application.quitting += () => SendEvent(new GameQuitEvent());
        }

        public void Quit()
        {
#if UNITY_EDITOR
            bool isEditor = false;
            isEditor = true;
            if (isEditor)
                UnityEditor.EditorApplication.isPlaying = false;
            else
#endif
                Application.Quit();
        }

        public bool CreateGame(ref string failedMsg)
        {
            var mainMenu = this.GetInstance<MainMenuUIController>();
            // TODO：应该从数据库中获取 ID 和名字
            var res = _network.CreateGame(new CreateNetworkArgs()
            {
                ipStr = mainMenu.IPAddressStr, 
                portStr = mainMenu.PortStr,
                maxPlayerCountStr = mainMenu.MaxPlayerCountStr,
                playerId = _id, 
                playerName = mainMenu.PlayerNameStr,
            });
            if (res == InspectionRes.None)
            {
                _isInGame = true;
                return true;
            }
            failedMsg = TransformInspectionRes(res);
            return false;
        }

        public void JoinGame(Action<bool, string> onCompleted)
        {
            var mainMenu = this.GetInstance<MainMenuUIController>();
            var task = _network.JoinGame(new CreateNetworkArgs()
            {
                ipStr = mainMenu.IPAddressStr,
                portStr = mainMenu.PortStr,
                playerId = _id,
                playerName = mainMenu.PlayerNameStr,
            }).ContinueWith(t =>
            {
                if (t.IsFaulted)
                {
                    onCompleted?.Invoke(false, "发生未知错误！");
                    // TODO：这是一步臭棋，以后需要改别的异常通知
                    if (IsEditorMode)
                        Debug.LogError(t.Exception.InnerException);
                    return;
                }
                var res = t.Result;
                if (res == InspectionRes.None)
                {
                    _isInGame = true;
                    onCompleted?.Invoke(true, null);
                }
                else
                {
                    var failedMsg = TransformInspectionRes(res);
                    onCompleted?.Invoke(false, failedMsg);
                }
            });
        }

        public void CloseGame()
        {
            _network.CloseGame();
            this.GetInstance<IPlayerSystem>().CloseGame();
            this.GetInstance<IUIManager>().ShowUI(UIType.MainMenu);
            this.GetInstance<IResourceManager>().CloseGame();
        }
        #endregion

        #region 回调方法

        #endregion
    }

}